﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Net;
using System.IO;
using System.Windows.Forms;
using System.Web;
//using System.Threading;
using System.Diagnostics;
namespace UGnome
{
    public enum HttpRequestId
    {
        Null = 0,
        GrabClanInfo,
        AllChanList,
        RoamList,
        ClanList
    }

    public class GrabClanInfoRequest : HttpRequest
    {
        public string Channel { get; protected set;}
        public string Realm { get; protected set; }
        public string gUrl { get; protected set; }

        public GrabClanInfoRequest(string gurl, string channel, string realm, string url, HttpRequestId id)
            : base(url, id)
        {
            Channel = channel;
            Realm = realm;
            gUrl = gurl;
        }
    }

    public class HttpRequest
    {
        public HttpRequestId Id { get; set; }
        public HttpWebRequest Request { get; set; }
        private string Url { get; set; }
        public HttpRequest(string url, HttpRequestId id)
        {
            Id = id;
            Request = (HttpWebRequest)WebRequest.Create(url);
            Url = url;
        }

        public override string ToString()
        {
            return Url;
        }
    }

    public class Manager
    {
        public List<string> AllChannels { get; private set; }
        public List<string> NextChannel { get; private set; }
        public List<string> ClanChannel { get; private set; }
        public Plugin Plugin { get; set; }

        public Manager()
        {
            AllChannels = new List<string>();
            NextChannel = new List<string>();
            ClanChannel = new List<string>();
        }

        public Manager(Plugin p)
        {
            Plugin = p;
            AllChannels = new List<string>();
            NextChannel = new List<string>();
            ClanChannel = new List<string>();
        }

        public bool IsAlphaNumeric(String str)
        {
            Regex regexAlphaNum = new Regex("[^a-zA-Z0-9]");
            return !regexAlphaNum.IsMatch(str);
        }

        // get bnet url to parse clan channel info
        public void GrabClanInfo(object url, object channel, object realm, object gUrl)
        {
            try
            {
                //string strResult;
                GrabClanInfoRequest request = new GrabClanInfoRequest((string)gUrl, (string)channel, (string)realm, (string)url, HttpRequestId.GrabClanInfo);
                //Send(request);
                Plugin.Q.Enqueue(request);

                //string clanName = ParseClanName(strResult);
                //string clanChief = ParseClanChief(strResult);
                //string clanCreated = ParseClanCreated(strResult);

                //string sendURL = (string)gUrl + "?newchannel=" + Encode((string)channel) + "&realm=" + Encode((string)realm) + "&clanchief=" + Encode(clanChief) + "&clanname=" + Encode(clanName) + "&clancreated=" + Encode(clanCreated);
                //Send(new HttpRequest(sendURL, HttpRequestId.Null));
                //HttpWebRequest Send = (HttpWebRequest)WebRequest.Create(sendURL);
                //HttpWebResponse SendResp = (HttpWebResponse)Send.GetResponse();
            }
            catch (Exception)
            {
                
            }
        }

        public string ParseClanName(string data)
        {
            if (data.Contains("<title>Warcraft III Ladder</title>") || data.Contains("<title>Frozen Throne Ladder</title>"))
            {
                return "";
            }

            try
            {
                string temp;
                int location;

                location = data.IndexOf("CLAN STUFF");
                temp = data.Substring(location, data.Length - location);
                location = temp.IndexOf("<span") + 6;
                temp = temp.Substring(location, temp.Length - location);
                location = temp.IndexOf(">") + 2;
                temp = temp.Substring(location - 1, temp.Length - location);
                location = temp.IndexOf(" [");
                temp = temp.Substring(0, location);

                return temp;
            }
            catch (Exception)
            {
                return "";
            }
        }

        public string ParseClanChief(string data)
        {
            if (data.Contains("<title>Warcraft III Ladder</title>") || data.Contains("<title>Frozen Throne Ladder</title>"))
            {
                return "";
            }

            try
            {
                string temp;
                int location;

                location = data.IndexOf("rank4") + 5;
                temp = data.Substring(location, data.Length - location);
                location = temp.IndexOf("PlayerName=") + 11;
                temp = temp.Substring(location, temp.Length - location);
                location = temp.IndexOf(">") + 2;
                temp = temp.Substring(location - 1, temp.Length - location);
                location = temp.IndexOf("</a");
                temp = temp.Substring(0, location);

                return temp;
            }
            catch (Exception)
            {
                return "";
            }
        }

        public  string ParseClanCreated(string data)
        {
            if (data.Contains("<title>Warcraft III Ladder</title>") || data.Contains("<title>Frozen Throne Ladder</title>"))
            {
                return "";
            }

            try
            {
                string temp;
                int location;

                location = data.IndexOf("Creation Date: ") + 15;
                temp = data.Substring(location, data.Length - location);
                location = temp.IndexOf(">") + 1;
                temp = temp.Substring(location, temp.Length - location);
                location = temp.IndexOf("<") - 1;
                temp = temp.Substring(0, location);

                return temp;
            }
            catch (Exception)
            {
                return "";
            }
        }

        public  string GetClanRealm(string realm)
        {
            switch (realm)
            {
                case "Azeroth":
                    return "classic";
                case "Lordaeron":
                    return "classic";
                case "Northrend":
                    return "classic";
                case "Kalimdor":
                    return "asialadders";
                default:
                    return "classic";
            }
        }

        // populate the whole channel list
        public  void PopulateAllChannels(string gUrl, string realm)
        {
            HttpRequest send = new HttpRequest(gUrl + String.Format("?p={0}&allchannels&realm={1}", Encode(Plugin.Password), Encode(realm)), HttpRequestId.AllChanList);
            //Send(send);
            Plugin.Q.Enqueue(send);
        }

        public void Send(HttpRequest data)
        {
            Debug.Print("Sending: {0}", data.ToString());
            data.Request.BeginGetResponse(FinishWebRequest, data);
        }

        public  void FinishWebRequest(IAsyncResult sender)
        {
            try
            {
                HttpRequest url = (HttpRequest)sender.AsyncState;

                HttpWebResponse HttpWResp = (HttpWebResponse)url.Request.GetResponse();

                string result;
                using (StreamReader sr = new StreamReader(HttpWResp.GetResponseStream()))
                {
                    result = sr.ReadToEnd();
                }

                switch (url.Id)
                {
                    case HttpRequestId.Null:
                        break;
                    case HttpRequestId.GrabClanInfo:
                        GrabClanInfoRequest claninfo = (GrabClanInfoRequest)url;
                        string clanName = ParseClanName(result);
                        string clanChief = ParseClanChief(result);
                        string clanCreated = ParseClanCreated(result);
                        
                        string channelname = (string)claninfo.Channel;

                        if (!claninfo.Channel.ToString().Contains(" "))
                        {
                            //string[] channel = claninfo.Channel.ToString().Split(' ');
                            //channelname = channel[1];
                            channelname = String.Format("Clan {0}", (string)claninfo.Channel);
                        }

                        string sendURL = (string)claninfo.gUrl + String.Format("?p={0}&newchannel={1}&realm={2}&clanchief={3}&clanname={4}&clancreated={5}", Encode(Plugin.Password), Encode(channelname), Encode((string)claninfo.Realm), Encode(clanChief), Encode(clanName), Encode(clanCreated));
                        //Send(new HttpRequest(sendURL, HttpRequestId.Null));
                        HttpRequest request = new HttpRequest(sendURL, HttpRequestId.Null);
                        Plugin.Q.Enqueue(request);
                        break;
                    case HttpRequestId.AllChanList:
                        GetAllChannels(result);
                        break;
                    case HttpRequestId.RoamList:
                        GetRoamList(result);
                        break;
                    case HttpRequestId.ClanList:
                        GetClanList(result);
                        break;
                }
            }
            catch (WebException ex)
            {
                Plugin.Bot.AddChat("#F0493C", String.Format("[UGnome] Error: {0}", ex.Message));
            }
        }

        // get all clan channels to cycle through and update
        public void GetClanList(string list)
        {
            string[] channels = list.Split(new char[] { '\n' });

            foreach (string channel in channels)
            {
                ClanChannel.Add(channel);
            }
        }

        // get next 50 channels to roam
        public void GetRoamList(string list)
        {
            string[] channels = list.Split(new char[] { '\n' });

            foreach (string channel in channels)
            {
                NextChannel.Add(channel);
            }
        }

        // get all available channels in the db
        public void GetAllChannels(string list)
        {
            string[] channels = list.Split(new char[] { '\n' });

            foreach (string channel in channels)
            {
                AddAllChannel(channel);
            }
        }

        /*public  void SendURL(object url)
        {
            MessageBox.Show((string)url);
            try
            {
                string strResult;
                HttpWebRequest reqFirstPage = (HttpWebRequest)WebRequest.Create((string)url);

                // timeout request after 10 seconds
                reqFirstPage.Timeout = 10000;
                //reqFirstPage.BeginGetResponse(HandleWebRequest, reqFirstPage);
                HttpWebResponse resURL = (HttpWebResponse)reqFirstPage.GetResponse();
                StreamReader srURL = new StreamReader(resURL.GetResponseStream());
                strResult = srURL.ReadToEnd();

                if (url.ToString().Contains("?nextchannel"))
                {
                    string[] channels = strResult.Split(new char[] { '\n' });

                    foreach (string channel in channels)
                    {
                        NextChannel.Add(channel);
                    }
                }
                else if (url.ToString().Contains("?allchannels"))
                {
                    string[] channels = strResult.Split(new char[] { '\n' });

                    foreach (string channel in channels)
                    {
                        AddAllChannel(channel);
                    }
                }
            }
            catch (Exception)
            {
            }
        }*/

        // add to entire available channel list
        public  void AddAllChannel(string newchannel)
        {
            bool exists = false;
            foreach (string channel in AllChannels)
            {
                if (channel.ToLower() == newchannel.ToLower())
                {
                    exists = true;
                }
            }

            if (!exists)
            {
                AllChannels.Add(newchannel);
            }
        }

        // find if a channel exists in the list (don't send URL if it does)
        public  bool FindAllChannel(string newchannel)
        {
            bool exists = false;
            foreach (string channel in AllChannels)
            {
                if (channel.ToLower() == newchannel.ToLower())
                {
                    exists = true;
                }
            }

            if (exists)
            {
                return true;
            }

            return false;
        }

        public  void FindChannels(string text, string gUrl, string realm)
        {
            string[] pieces = text.Split(new char[] { ' ' });
            for (int i = 0; i < pieces.Length; i++)
            {
                string piece = pieces[i];

                if ((String.Compare(piece, "clan", true) == 0 || String.Compare(piece, "op", true) == 0) &&
                    i < pieces.Length - 1)
                {
                    string clan = pieces[i + 1].Replace(".", "").Replace("!", "").Replace(",", "").Replace("?", "");
                    string channel = piece + ' ' + clan;

                    bool isclan = String.Compare(piece, "clan", true) == 0;
                    bool islegal = !isclan && clan.Length <= 15 && clan.Length >= 2 || (clan.Length <= 4 && clan.Length >= 2 && IsAlphaNumeric(clan));

                    if (islegal && !FindAllChannel(channel))
                    {
                        AddAllChannel(channel);

                        if (piece.ToLower() == "clan")
                        {
                            string bnetURL = "http://" + GetClanRealm(realm) + ".battle.net/war3/ladder/w3xp-clan-profile.aspx?ClanTag=" + clan + "&Gateway=" + realm + "&SortField=rank&SortDir=Desc&PageNo=1";

                            /*ThreadStart starter = delegate { GrabClanInfo(bnetURL, channel, realm, gUrl); };
                            Thread thread = new Thread(starter);
                            thread.Start();*/
                            GrabClanInfo(bnetURL, channel, realm, gUrl);
                        }
                        else if (piece.ToLower() == "op")
                        {
                            HttpRequest send = new HttpRequest(gUrl + String.Format("?p={0}&newchannel={1}&realm={2}", Encode(Plugin.Password), Encode(channel), Encode(realm)), HttpRequestId.Null);
                            //Send(send);
                            Plugin.Q.Enqueue(send);
                        }

                        // Query to see if channel already exists
                        /*int Result = MySQL.QueryGet("SELECT * FROM `gnome_channels` WHERE `channel` = '" + MySQL.Escape(channel) + "' AND `realm` = '" + BotRealm + "' LIMIT 1").RowCount;

                        // if doesn't exist then insert new channel data
                        if (Result == 0)
                        {
                            if (piece.ToLower() == "clan")
                            {
                                string bnetURL = Manager.GrabURL("http://" + Manager.GetClanRealm(BotRealm) + ".battle.net/war3/ladder/w3xp-clan-profile.aspx?ClanTag=" + clan + "&Gateway=" + BotRealm + "&SortField=rank&SortDir=Desc&PageNo=1");
                                string clanName = Manager.ParseClanName(bnetURL);
                                string clanChief = Manager.ParseClanChief(bnetURL);
                                string clanCreated = Manager.ParseClanCreated(bnetURL);

                                //MySQL.QueryPut("INSERT INTO `gnome_channels` (channel, realm, first_seen, last_seen, clan_chief, clan_fullname, clan_creation) VALUES ('" + MySQL.Escape(channel) + "', '" + BotRealm + "', " + timeEpoch + ", 0, '" + MySQL.Escape(clanChief) + "', '" + MySQL.Escape(clanName) + "', '" + MySQL.Escape(clanCreated) + "')");
                                Query query = new Query(QueryType.Put, "INSERT INTO `gnome_channels` (channel, realm, first_seen, last_seen, clan_chief, clan_fullname, clan_creation) VALUES ('" + MySQL.Escape(channel) + "', '" + BotRealm + "', " + timeEpoch + ", 0, '" + MySQL.Escape(clanChief) + "', '" + MySQL.Escape(clanName) + "', '" + MySQL.Escape(clanCreated) + "')");
                                Q.Enqueue(query);
                            }
                            else if (piece.ToLower() == "op")
                            {
                                //MySQL.QueryPut("INSERT INTO `gnome_channels` (channel, realm, first_seen, last_seen) VALUES ('" + MySQL.Escape(channel) + "', '" + BotRealm + "', " + timeEpoch + ", 0)");
                                Query query = new Query(QueryType.Put, "INSERT INTO `gnome_channels` (channel, realm, first_seen, last_seen) VALUES ('" + MySQL.Escape(channel) + "', '" + BotRealm + "', " + timeEpoch + ", 0)");
                                Q.Enqueue(query);
                            }
                        }*/
                    }
                }
            }
        }

        public string AddAppend(string username, string userproduct, string realm)
        {
            string userproductU = userproduct.ToUpper();

            switch (userproductU)
            {
                case "STAR":
                case "SEXP":
                case "W2BN":
                case "D2DV":
                case "D2XP":
                case "SSHR":
                case "JSTR":
                case "DRTL":
                case "DSHR":
                    if (username.ToLower().EndsWith("@useast") || username.ToLower().EndsWith("@uswest") || username.ToLower().EndsWith("@europe") || username.ToLower().EndsWith("@asia"))
                    {
                        return username;
                    }
                    else
                    {
                        return String.Format("{0}@{1}", username, GetServer(realm.ToLower()));
                    }
                case "WAR3":
                case "W3XP":
                    if (username.ToLower().EndsWith("@azeroth") || username.ToLower().EndsWith("@lordaeron") || username.ToLower().EndsWith("@northrend") || username.ToLower().EndsWith("@kalimdor"))
                    {
                        return username;
                    }
                    else
                    {
                        return String.Format("{0}@{1}", username, realm);
                    }
            }

            return String.Format("{0}@Unknown", username);
        }

        public string GetServer(string realm)
        {
            realm = realm.ToLower();

            switch(realm)
            {
                case "azeroth":
                    return "USEast";
                case "lordaeron":
                    return "USWest";
                case "northrend":
                    return "Europe";
                case "kalimdor":
                    return "Asia";
            }

            return "Unknown";
        }

        // get realm from Bot's server
        public string GetRealmFromServer(string server)
        {
            server = server.ToLower();

            switch (server)
            {
                case "useast.battle.net":
                case "63.240.202.126":
                case "63.240.202.127":
                case "63.240.202.128":
                case "63.240.202.129":
                case "63.240.202.130":
                case "63.240.202.131":
                case "63.240.202.134":
                case "63.240.202.138":
                case "63.240.202.139":
                case "63.240.202.120":
                case "63.240.202.121":
                case "63.240.202.122":
                    return "Azeroth";
                case "uswest.battle.net":
                case "63.241.83.7":
                case "63.241.83.8":
                case "63.241.83.9":
                case "63.241.83.11":
                case "63.241.83.12":
                case "63.241.83.13":
                case "63.241.83.107":
                case "63.241.83.108":
                case "63.241.83.109":
                case "63.241.83.110":
                case "63.241.83.111":
                case "63.241.83.112":
                    return "Lordaeron";
                case "europe.battle.net":
                case "213.248.106.204":
                case "213.248.106.65":
                case "213.248.106.66":
                case "213.248.106.67":
                case "213.248.106.68":
                case "213.248.106.200":
                case "213.248.106.201":
                case "213.248.106.202":
                    return "Northrend";
                case "asia.battle.net":
                case "211.233.0.74":
                case "211.233.0.75":
                case "211.233.0.76":
                case "211.233.0.78":
                case "211.233.0.79":
                case "211.233.0.80":
                case "211.233.0.49":
                case "211.233.0.50":
                case "211.233.0.51":
                case "211.233.0.52":
                case "211.233.0.53":
                case "211.233.0.54":
                case "211.233.0.55":
                case "211.233.0.56":
                case "211.233.0.57":
                case "211.233.0.58":
                case "211.233.0.59":
                case "211.233.0.60":
                case "211.233.0.61":
                case "211.233.0.62":
                case "211.233.0.63":
                case "211.233.0.64":
                case "211.233.0.72":
                case "211.233.0.73":
                    return "Asia";
            }

            return "Unknown";
        }

        public string ReverseString(string s)
        {
            char[] arr = s.ToCharArray();
            Array.Reverse(arr);
            return new string(arr);
        }

        public  string Encode(string text)
        {
            return HttpUtility.UrlEncode(text);
        }
    }
}
